package projects.defaultProject.models.mobilityModels;

import java.util.Random;

import sinalgo.configuration.Configuration;
import sinalgo.configuration.CorruptConfigurationEntryException;
import sinalgo.models.MobilityModel;
import sinalgo.nodes.Node;
import sinalgo.nodes.Position;
import sinalgo.tools.statistics.Distribution;
import sinalgo.tools.statistics.UniformDistribution;
import sinalgo.tools.statistics.WrappedGaussianDistribution;

public class CorrelatedRandomWalk extends MobilityModel {

	private double ml; //scaling parameter for the movement length
	private double cp; //concentration parameter
	private boolean u; //uniform movement or not.
	private int tp; //timePause
	
	private Position currentPosition;
	private double angle;
	private Random movementLengthDistribution;
	private WrappedGaussianDistribution angleDistribution;
	private int count;
	
	public CorrelatedRandomWalk() throws CorruptConfigurationEntryException {
		ml = Configuration.getDoubleParameter("CorrelatedRandomWalk/ml");
		cp = Configuration.getDoubleParameter("CorrelatedRandomWalk/cp");
		u = Configuration.getBooleanParameter("CorrelatedRandomWalk/u");
		tp = Configuration.getIntegerParameter("CorrelatedRandomWalk/tp");
		
		movementLengthDistribution = Distribution.getRandom();
		angleDistribution = new WrappedGaussianDistribution(0, cp, 1);
		count = 0;
	}
	
	@Override
	public Position getNextPos(Node n) {

		if ( currentPosition == null ) {
			currentPosition = new Position();
			currentPosition.assign( n.getPosition() );
			angle = UniformDistribution.nextUniform(0, 2*Math.PI);
		}
		

		if (++count % tp == 0) {
			Position nextPosition = new Position(0, 0, 0);
			do {
				double d = u ? ml : movementLengthDistribution.nextFloat()*ml;
				nextPosition.xCoord = currentPosition.xCoord + d * Math.cos(angle);
				nextPosition.yCoord = currentPosition.yCoord + d * Math.sin(angle);
				
				//angle += angleDistribution.nextSample();
				
				if ( nextPosition.xCoord > Configuration.dimX || nextPosition.xCoord < 0 || 
						nextPosition.yCoord > Configuration.dimY || nextPosition.yCoord < 0 ) 
					angle += Math.PI/2;
				else
					angle += angleDistribution.nextSample();
			} while ( nextPosition.xCoord > Configuration.dimX || nextPosition.xCoord < 0 || 
					nextPosition.yCoord > Configuration.dimY || nextPosition.yCoord < 0 || 
					nextPosition.zCoord > Configuration.dimZ || nextPosition.zCoord < 0 );

			currentPosition.assign( nextPosition );
			return nextPosition;
	
		} else {
			return currentPosition;
		}
	}

}
